/**
    算法描述：
    核心问题：
    解决所需数据结构+算法：
**/
#include<bits/stdc++.h>
using namespace std;

struct edge{
	int x, y, pre;
}a[100010];
int alen = 0, last[10010] = {0};

int ans = 0, match[10010] = {0};
bool v[10010] = {false};

void ins(int x, int y) {
	a[++alen] = edge{x, y, last[x]};
	last[x] = alen;
}

bool findCow(int x) {
//	能否找到自己的母牛 
	for (int k=last[x]; k; k=a[k].pre) {
		int y = a[k].y;
		if (!v[y]) {
			v[y] = true;
			if(match[y] == 0 || findCow(match[y])) {
				match[y] = x;
				return true;
			}
		}
	}
	return false;
}

int main() {
	int n, m, k;
	scanf("%d%d%d", &n, &m, &k);
	while(k--) {
		int x, y;
		scanf("%d%d", &x, &y);
		ins(x, y);
	}
	for (int i=1; i<=n; i++) {

/*      这一步至关重要，每一轮非连通的公牛顶点在寻找母牛的时候，
        是默认之前被选择的母牛都是作废的，以后面的公牛优先。
        但是在递归调用的findCow方法时，又是必须要保护前面公牛的选择，
        或者说递归调用时就是在更换该公牛已有的选择。
        ！！！因此，需要v数组进行判断究竟是for直接调用的findCow还是递归
        调用的findCow。这点是相当重要的。
*/

		memset(v, false, sizeof(v));


		if (findCow(i))
			ans++;
	}
	printf("%d", ans);
	return 0;
}